`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Wuhan University
// Engineer: Yu Zihao
// 
// Create Date: 2021/08/10 19:30:35
// Design Name: 
// Module Name: CPUSTM
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision: V1.0
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module CPUSTM(clk,reset,opcode,op,
              load_addr,load_ir,load_pc,addr_sel,mem_cmd,reset_pc,pcsel,
              nsel,write, vsel, asel, bsel, loada, loadb, loadc, loads);
input clk, reset;
input [2:0] opcode;
input [1:0] op,mem_cmd;
output addr_sel,load_pc,load_ir,reset_pc,load_addr;
output [2:0] pcsel;
output reg [2:0] nsel;//one-hot
//nsel = 001 Rm
//nsel = 010 Rd
//nsel = 100 Rn
output write, asel, bsel, loada, loadb, loadc, loads;
output [1:0] vsel;
`define CW 9
reg [`CW-1:0] conSignal;
assign {write, vsel, asel, bsel, loada, loadb, loadc, loads} = conSignal;
`define LCW 10
`define LC_NONE `LCW'b0001000001
reg [`LCW-1:0] lpcConSignal;
assign {reset_pc,load_ir,load_pc,addr_sel,mem_cmd,load_addr,pcsel} = lpcConSignal;

`define SW 6
`define RST      `SW'd0  //CPU idle
`define WIMM     `SW'd1  //MOV Rn, #<im8>
`define WRmS     `SW'd2  //MOV Rn, #<im8>
`define WRmS1    `SW'd3  //MOV Rn, #<im8>
`define WRmS2    `SW'd4  //MOV Rn, #<im8>
`define IF1      `SW'd5  //load pc form memery
`define IF2      `SW'd6  //load pc to instruction register
`define UpdatePC `SW'd7  
`define HALT     `SW'd8  //HALT
`define ADD      `SW'd9  //ADD Rd,Rn,Rm{,<sh_op>}��load a
`define ADD1     `SW'd10  //load b
`define ADD2     `SW'd11  //load c
`define ADD3     `SW'd12  //write back
`define CMP      `SW'd13  //CMP Rn,Rm{,<sh_op>}
`define CMP1     `SW'd14  //CMP
`define CMP2     `SW'd15  //CMP
`define AND      `SW'd16  //AND
`define AND1     `SW'd17  //AND
`define AND2     `SW'd18  //AND
`define AND3     `SW'd19  //AND
`define MVN      `SW'd20  //MVN
`define MVN1     `SW'd21  //MVN
`define MVN2     `SW'd22  //MVN
`define LDR      `SW'd23  //LDR
`define LDR1     `SW'd24  //LDR
`define LDR2     `SW'd25  //LDR
`define LDR3     `SW'd26  //LDR
`define LDR4     `SW'd27  //LDR
`define STR      `SW'd28  //STR
`define STR1     `SW'd29  //STR
`define STR2     `SW'd30  //STR
`define STR3     `SW'd31  //STR
`define pushPC   `SW'd32  //save next PC to R7
`define UPPC     `SW'd33  //manual update pc form pcsel=010
`define UPPC1    `SW'd34  //manual update pc form pcsel=100

wire [`SW-1:0] state;
reg [`SW-1:0] next_state;
VDFFE #(`SW) STATE(.clk(clk), .in(next_state), .load(1'b1), .out(state), .rst(reset));

//ע�⣺
always @(*)begin
    casex({reset, state, opcode, op})//���state=x������ƥ���κ�״̬
    //RESET
    {1'b1,{`SW{1'bx}},3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`RST, 3'b0, `CW'b0, `LC_NONE};               //RESET -> RST
    //RST
    {1'b0,       `RST,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1, 3'b0, `CW'b0, `LCW'b1011000001};               //RST -> IF1
    //IF1
    {1'b0,       `IF1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF2, 3'b0, `CW'b0, `LCW'b0001010001};               //IF1 -> IF2
    //IF2
    {1'b0,       `IF2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`UpdatePC, 3'b0, `CW'b0, `LCW'b0101010001};               //IF2 -> UpdatePC    
    //UpdatePC
    {1'b0,      `UpdatePC,3'b111,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`HALT, 3'b0, `CW'b0, `LC_NONE};                    //UpdatePC -> HALT
    {1'b0,      `UpdatePC,3'b110,2'b10} : {next_state, nsel, conSignal, lpcConSignal} = {`WIMM, 3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> MOV Rn, #<im8>
    {1'b0,      `UpdatePC,3'b110,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`WRmS, 3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> MOV Rn, Rm{,<sh_op>}
    {1'b0,      `UpdatePC,3'b101,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`ADD,  3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> ADD Rd,Rn,Rm{,<sh_op>}
    {1'b0,      `UpdatePC,3'b101,2'b01} : {next_state, nsel, conSignal, lpcConSignal} = {`CMP,  3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> CMP
    {1'b0,      `UpdatePC,3'b101,2'b10} : {next_state, nsel, conSignal, lpcConSignal} = {`AND,  3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> AND
    {1'b0,      `UpdatePC,3'b101,2'b11} : {next_state, nsel, conSignal, lpcConSignal} = {`MVN,  3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> MVN
    {1'b0,      `UpdatePC,3'b011,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`LDR,  3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> LDR
    {1'b0,      `UpdatePC,3'b100,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`STR,  3'b0, `CW'b0, `LCW'b0011000001};               //UpdatePC -> STR
    {1'b0,      `UpdatePC,3'b001,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`UPPC,  3'b0, `CW'b0, `LCW'b0011000001};          //UpdatePC -> UPPC
    {1'b0,      `UpdatePC,3'b010,2'b1x} : {next_state, nsel, conSignal, lpcConSignal} = {`pushPC,  3'b0, `CW'b0, `LCW'b0011000001};          //UpdatePC -> pushPC
    {1'b0,      `UpdatePC,3'b010,2'b00} : {next_state, nsel, conSignal, lpcConSignal} = {`UPPC1,  3'b010, `CW'b0, `LCW'b0011000001};          //UpdatePC -> UPPC1
    //HALT
    {1'b0,      `HALT,    3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`HALT, 3'b0, `CW'b0, `LCW'b0011000001};               //HALT -> HALT dead
    //MOV Rn, #<im8>
    {1'b0,      `WIMM,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`IF1, 3'b100, `CW'b1_1000_0000, `LC_NONE};   //MOV Rn, #<im8> -> IF1
    //MOV Rn, Rm{,<sh_op>}
    {1'b0,      `WRmS,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`WRmS1, 3'b001, `CW'b0_0010_0100, `LC_NONE};   //MOV Rn, #<im8>  load Rm -> WRmS1
    {1'b0,      `WRmS1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`WRmS2, 3'b001, `CW'b0_0010_0010, `LC_NONE};   //MOV Rn, #<im8>  load C -> WRmS2
    {1'b0,      `WRmS2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,   3'b010, `CW'b1_0000_0000, `LC_NONE};   //MOV Rn, #<im8>  WB -> IF1
    //ADD Rd,Rn,Rm{,<sh_op>}
    {1'b0,      `ADD,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`ADD1, 3'b100, `CW'b0_0000_1000, `LC_NONE};   //ADD  -> ADD1: loada (Rn)
    {1'b0,      `ADD1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`ADD2, 3'b001, `CW'b0_0000_0100, `LC_NONE};   //ADD1 -> ADD2: loadb (Rm)
    {1'b0,      `ADD2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`ADD3, 3'b001, `CW'b0_0000_0011, `LC_NONE};   //ADD2 -> ADD3
    {1'b0,      `ADD3,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b010, `CW'b1_0000_0000, `LC_NONE};   //ADD3 -> IF1: Rd
    //CMP Rn,Rm{,<sh_op>}
    {1'b0,      `CMP,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`CMP1, 3'b100, `CW'b0_0000_1000, `LC_NONE};   //CMP  -> CMP1: loada (Rn)
    {1'b0,      `CMP1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`CMP2, 3'b001, `CW'b0_0000_0100, `LC_NONE};   //CMP1 -> CMP2: loadb (Rm)
    {1'b0,      `CMP2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b001, `CW'b0_0000_0001, `LC_NONE};   //CMP2 -> IF1:loads
    //AND Rd,Rn,Rm{,<sh_op>}
    {1'b0,      `AND,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`AND1, 3'b100, `CW'b0_0000_1000, `LC_NONE};   //AND  -> AND1: loada (Rn)
    {1'b0,      `AND1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`AND2, 3'b001, `CW'b0_0000_0100, `LC_NONE};   //AND1 -> AND2: loadb (Rm)
    {1'b0,      `AND2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`AND3, 3'b001, `CW'b0_0000_0010, `LC_NONE};   //AND2 -> AND3
    {1'b0,      `AND3,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b010, `CW'b1_0000_0000, `LC_NONE};   //AND3 -> IF1: Rd
    //MVN Rd,Rm{,<sh_op>}
    {1'b0,      `MVN,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`MVN1, 3'b001, `CW'b0_0000_0100, `LC_NONE};   //MVN  -> MVN1: loadb (Rm)
    {1'b0,      `MVN1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`MVN2, 3'b001, `CW'b0_0000_0010, `LC_NONE};   //MVN1 -> MVN2: alu loadc
    {1'b0,      `MVN2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b010, `CW'b1_0000_0000, `LC_NONE};   //MVN2 -> IF1: Rd
    
    //LDR
    {1'b0,      `LDR,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`LDR1, 3'b100, `CW'b0_0001_1000, `LC_NONE};   //LDR  -> LDR1: loada (Rn)
    {1'b0,      `LDR1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`LDR2, 3'b100, `CW'b0_0001_0010, `LC_NONE};   //LDR1 -> LDR2: loadb (Rm)
    {1'b0,      `LDR2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`LDR3, 3'b100, `CW'b0_0000_0000, `LCW'b0001001001};   //LDR2 -> LDR3
    {1'b0,      `LDR3,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`LDR4,  3'b010, `CW'b0_0000_0000, `LCW'b0000010001};   //LDR3 -> LDR4
    {1'b0,      `LDR4,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,   3'b010, `CW'b1_1100_0000, `LCW'b0000010001};   //LDR4 -> IF1: Rd
    //STR
    {1'b0,      `STR,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal}  = {`STR1, 3'b100, `CW'b0_0001_1000, `LC_NONE};   //STR  -> STR1: loada (Rn)
    {1'b0,      `STR1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`STR2, 3'b100, `CW'b0_0001_0010, `LC_NONE};   //STR1 -> STR2: loadb (Rm)
    {1'b0,      `STR2,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`STR3, 3'b010, `CW'b0_0000_0000, `LCW'b0001001001};   //STR2 -> STR3
    {1'b0,      `STR3,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b010, `CW'b0_0000_0000, `LCW'b0000100001};   //STR3 -> IF1: Rd
    
    //UPPC
    {1'b0,      `UPPC,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b0, `CW'b0_0000_0000, `LCW'b0011000010};          //UPPC -> IF1
    //UPPC1
    {1'b0,      `UPPC1,3'bxxx,2'bxx} : {next_state, nsel, conSignal, lpcConSignal} = {`IF1,  3'b010, `CW'b0_0000_0000, `LCW'b0011000100};          //UPPC1 -> IF1
    //pushPC
    {1'b0,      `pushPC,3'bxxx,2'bx1} : {next_state, nsel, conSignal, lpcConSignal}  = {`UPPC, 3'b100, `CW'b1_0100_0000, `LC_NONE};   //STR  -> UPPC
    {1'b0,      `pushPC,3'bxxx,2'bx0} : {next_state, nsel, conSignal, lpcConSignal}  = {`UPPC1, 3'b100, `CW'b1_0100_0000, `LC_NONE};   //STR  -> UPPC1
    
    
//assign {write, --- vsel, asel, bsel,  --- loada, loadb, loadc, loads} = conSignal;
//assign {reset_pc,load_ir,load_pc,addr_sel,mem_cmd,load_addr,pcsel} = lpcConSignal;
//  vsel
//    11:mdata
//    10:sximm8
//    01:{8'b0,PC}
//    00:loadc
//mem_cmd
//`define MNONE  2'00
//`define MREAD  2'01
//`define MWRITE 2'10
//read write num MUX with one-hot
//nsel = 001 Rm
//nsel = 010 Rd
//nsel = 100 Rn

    default : {next_state, nsel, conSignal, lpcConSignal} = {{`SW{1'bx}}, 3'bxxx, `CW'bxxxxxxxx, `LCW'bxxxxxxxxxx};
    endcase
end

endmodule
